#region The MIT License
// The MIT License
// 
// Copyright (c) 2009 octalforty studios
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#endregion
using System;
using System.Text.RegularExpressions;
using octalforty.Componento.Shared.SemanticModel;

namespace octalforty.Componento.ComponentModel.Installation.FileSystem
{
    public abstract class FileSystemManifestProviderBase : IComponentManifestProvider
    {
        #region IComponentManifestProvider Members
        /// <summary>
        /// Verifies whether current <see cref="IComponentManifestProvider"/> can retrieve manifest from <paramref name="uri"/>.
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public virtual bool CanProvideManifestFrom(Uri uri)
        {
            return uri.Scheme == "file";
        }

        /// <summary>
        /// Retrieves <see cref="ComponentManifest"/> from <paramref name="uri"/> for package <paramref name="componentName"/> with
        /// version requirement <paramref name="versionSpecification"/>.
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="componentName"></param>
        /// <param name="versionSpecification"></param>
        /// <returns></returns>
        public virtual ComponentManifest GetComponentManifest(string componentName, Uri uri, VersionSpecification versionSpecification)
        {
            Version version = GetFileSystemEntryVersion(uri, componentName, versionSpecification);
            if (versionSpecification != null && !versionSpecification.Matches(version))
                return null;

            return new ComponentManifest(componentName, version, new Resource(uri, 0));
        }
        #endregion

        private static Version GetFileSystemEntryVersion(Uri uri, string packageName, VersionSpecification versionSpecification)
        {
            //
            // First we need to try and extract version number from filesystem entry name. For instance,
            // given a package name "nhibernate" and URI "file:///d:/nhibernate-2.1.0.zip",
            // we can (by convention) say that package version is 2.1.0.
            string localPath = uri.LocalPath;
            string pattern = string.Format(@"{0}\-(?<Version>\d+(\.\d+){{0,3}})", packageName);
            
            Regex versionExtractionRegex = new Regex(pattern, RegexOptions.IgnoreCase);

            if(versionExtractionRegex.IsMatch(localPath))
                return new Version(versionExtractionRegex.Match(localPath).Groups["Version"].Value);

            //
            // Otherwise, use version requirement (if it's present) as a package version.
            return versionSpecification != null && versionSpecification.Version != null ?
                versionSpecification.Version :
                null;
        }
    }
}
